/****************************************Copyright (c)****************************************************

**--------------File Info---------------------------------------------------------------------------------
** File name:                app_task.h
** Last modified Date:       2024.11.18
** Last Version:             Ver:1.0
** Descriptions:             温控任务
**
**--------------------------------------------------------------------------------------------------------
** Created by:               adm
** Created date:             2024.11.18
** Version:                  Ver:1.0
** Descriptions:             温控任务
**--------------------------------------------------------------------------------------------------------*/
#include "app_task.h"
#include "stdlib.h"
#include "string.h"

#define Temp_coeff          (0.9725f)       //板载传感器温度校正系数

//温湿度全局变量
__IO float shtxx_t_A;
__IO float shtxx_h_A;
__IO float shtxx_t_B;
__IO float shtxx_h_B;

//设定参数全局变量
__IO float set_temp;                        //设定温度
__IO float alarm_temp;                      //告警温度
__IO uint16_t set_time;                     //设定恒温时长，单位分钟
__IO uint16_t current_time = 0;             //当前时间，单位分钟
__IO uint8_t ctrl_start = 0;                //恒温控制启动  0 停止   1 启动
__IO int16_t pwm_value;                     //温控pwm值
__IO uint16_t voltage;                      //电压全局变量
__IO uint8_t error_count = 0;               //读取错误计数器


//温度数据存储缓冲区
uint16_t temp1s_buff[125] = {0};
uint16_t temp2s_buff[125] = {0};
uint16_t temp5s_buff[125] = {0};
uint16_t temp15s_buff[125] = {0};
uint16_t temp30s_buff[125] = {0};
uint16_t temp1m_buff[125] = {0};
uint16_t temp5m_buff[125] = {0};
uint16_t temp10m_buff[125] = {0};
uint16_t temp15m_buff[125] = {0};

SSD1306_VERTEX chart_buff[125];
uint16_t temp_chart_range;                  //温度曲线量程范围，已设定温度值为中心，±0.5 ±1 ±2 ±5 ±10 ±20
uint16_t temp_chart_refreshcycle;           //温度曲线刷新周期，单位秒，1s 2s 5s 30s 60s ......

//保存用户数据结构体变量
user_save_data_t user_save_data;

//系统标志
__IO uint8_t Interface_flag = 0;            //当前界面标志         0 控制界面    1 设置菜单界面
__IO uint8_t timed_comp_flag = 0;           //定时任务完成标志     0 未完成      1 已完成
__IO uint8_t alarm_status_flag = 0;         //报警提示音标志       0 不报警      1 发出报警音
__IO uint8_t Screensavers_status = 0;       //屏保状态 0 正常显示  1 低亮度显示  2 关闭屏幕
__IO uint16_t Screensavers_count = 0;       //屏保计数器
__IO uint32_t Shutdown_count = 0;           //自动关机计数器
__IO uint64_t current_second = 0;           //当前秒计数值

//设置菜单项目字符串变量
#define MENU_ITEM_MAX		11
const char *menu_string[] = {
    "mode",
    "SETt",
    "ALAt",
    "time",
    "Kp  ",
    "Ki  ",
    "Kd  ",
    "Sa_t",
    "Ct_t",
    "IC_s",
    "Flt ",
};

static char menu_value_string[MENU_ITEM_MAX][10] = {""};

//提示音乐谱
const uint16_t tone0[8] = {M1, 300, M3, 300, M5, 300, H1, 500};
const uint16_t tone1[8] = {H1, 300, M5, 300, M3, 300, M1, 500};
const uint16_t tone2[8] = {M4, 300, M1S, 300, M2S, 300, L5S, 500};
const uint16_t tone3[8] = {L5S, 300, M2S, 300, M4, 300, M1S, 500};

//参数设置局部变量
static __IO uint8_t set_day;                 //时长设定 天
static __IO uint8_t set_hour;                //时长设定 小时
static __IO uint8_t set_minute;              //时长设定 分钟
static __IO uint8_t set_temp_int;            //温度设定 整数部分
static __IO uint8_t set_temp_fractional;     //温度设定 小数部分
static __IO uint8_t alarm_temp_int;          //告警温度 整数部分
static __IO uint8_t alarm_temp_fractional;   //告警温度 小数部分
static __IO uint8_t set_pos = 0;             //当前设置参数位置
static __IO uint8_t Current_line = 0;
static __IO uint8_t Refresh_flag = 1;

/**
  * @brief    清除全部按键标志
  * @param    None
  * @retval   None
  */
void clear_all_button_flag(void)
{
    BUTTON_SINGLE_Click_Flag = 0;
    BUTTON_DOUBLE_Click_Flag = 0;
    BUTTON_SHORT_PRESS_Flag = 0;
//    BUTTON_LONG_PRESS_Flag = 0;

    K1_SINGLE_Click_Flag = 0;
    K1_DOUBLE_Click_Flag = 0;
    K1_SHORT_PRESS_Flag = 0;
//    K1_LONG_PRESS_Flag = 0;

    K2_SINGLE_Click_Flag = 0;
    K2_DOUBLE_Click_Flag = 0;
    K2_SHORT_PRESS_Flag = 0;
//    K2_LONG_PRESS_Flag = 0;

    Screensavers_count = 0;         //屏保计数器清零
    Shutdown_count = 0;             //自动关机计数器清零
}

/**
  * @brief  获取外部电压值
  * @param  none
  * @retval 返回以mV为单位的电压值
  */
uint16_t get_voltage_value(void)
{
    uint16_t ret = 0;

    adc_ordinary_software_trigger_enable(ADC1, TRUE);   //软件触发读取一次ADC测量值

    while(!adc_flag_get(ADC1, ADC_CCE_FLAG));

    ret = adc_ordinary_conversion_data_get(ADC1);

    ret = (uint16_t)((99.2f * (float)ret) / 22.0f);     //计算实际电压值，单位是mV

    ret = KalmanFilter_voltage.updateEstimate(&KalmanFilter_voltage,  (float)ret);                   //对本次测量值进行kalman滤波处理
    // ret = updateEstimate((float)ret);                   //对本次测量值进行kalman滤波处理
    return ret;
}

/**
  * @brief  获取存储的用户数据
  * @param  用户存储数据指针
  * @retval none
  */
void get_user_data(user_save_data_t *user_data)
{
    uint32_t flash_size;
    uint16_t sector_size;
    uint32_t user_data_addr;
    uint16_t user_data_offset = 0;

    flash_size = (*(uint32_t*)(0x1FFFF7E0)) << 10;
    sector_size = 2048;                                         //每扇区字节数
    user_data_addr = 0x08000000 + flash_size - sector_size;     //计算用户数据起始地址

    if(*(uint16_t*)(user_data_addr + user_data_offset) == 0xFFFF) {    //如果用户数据区数据为空，则用户数据设置为默认值
        user_data->user_set_temp = 3000;
        user_data->user_alarm_temp = 5000;
        user_data->user_set_time = 30;
        user_data->Kp = 3000;               //默认300
        user_data->Ki = 2;                  //默认0.02
        user_data->Kd = 0;                  //默认0
        user_data->scr_save_time = 60;      //默认60分钟屏幕保护
        user_data->shutdown_time = 60;      //默认60秒进入待机模式
        user_data->select_data.mode_select = 0;     //默认温度计模式
        user_data->select_data.filter_mode = 0;     //默认不滤波
        user_data->select_data.sensor_select = 0;   //默认使用内置传感器

        return;
    }

    while(1) {
        user_data->user_set_temp   = *(uint16_t*)(user_data_addr + user_data_offset);
        user_data->user_alarm_temp = *(uint16_t*)(user_data_addr + user_data_offset + 2);
        user_data->user_set_time   = *(uint16_t*)(user_data_addr + user_data_offset + 4);
        user_data->Kp = *(uint16_t*)(user_data_addr + user_data_offset + 6);
        user_data->Ki = *(uint16_t*)(user_data_addr + user_data_offset + 8);
        user_data->Kd = *(uint16_t*)(user_data_addr + user_data_offset + 10);
        user_data->scr_save_time = *(uint8_t*)(user_data_addr + user_data_offset + 12);
        user_data->shutdown_time = *(uint8_t*)(user_data_addr + user_data_offset + 13);
        user_data->select_data.data = *(uint8_t*)(user_data_addr + user_data_offset + 14);
        user_data->free_data = *(uint8_t*)(user_data_addr + user_data_offset + 15);


        user_data_offset = user_data_offset + sizeof(user_save_data);           //偏移到下一组数据起始地址

        if(*(uint16_t*)(user_data_addr + user_data_offset) == 0xFFFF || (user_data_offset >= (sector_size - sizeof(user_save_data)))) {
            break;      //上一组数据有效，退出
        }
    }

    return;
}


/**
  * @brief  保存用户数据
  * @param  用户存储数据指针
  * @retval none
  */
void save_user_data(user_save_data_t *user_data)
{
    uint32_t flash_size;
    uint16_t sector_size;
    uint32_t user_data_addr;
    uint16_t user_data_offset = 0;

    flash_size = (*(uint32_t*)(0x1FFFF7E0)) << 10;
    sector_size = 2048;                                 //每扇区字节数
    user_data_addr = 0x08000000 + flash_size - sector_size;     //计算用户数据起始地址

    while(1) {
        if((*(uint16_t*)(user_data_addr + user_data_offset) == 0xFFFF) && \
           (*(uint16_t*)(user_data_addr + user_data_offset + 2) == 0xFFFF) && \
           (*(uint16_t*)(user_data_addr + user_data_offset + 4) == 0xFFFF)) {

            /* 进入临界区 */
            taskENTER_CRITICAL();

            //保存用户数据
            flash_unlock();
            flash_halfword_program(user_data_addr + user_data_offset, user_data->user_set_temp);
            flash_halfword_program(user_data_addr + user_data_offset + 2, user_data->user_alarm_temp);
            flash_halfword_program(user_data_addr + user_data_offset + 4, user_data->user_set_time);
            flash_halfword_program(user_data_addr + user_data_offset + 6, user_data->Kp);
            flash_halfword_program(user_data_addr + user_data_offset + 8, user_data->Ki);
            flash_halfword_program(user_data_addr + user_data_offset + 10, user_data->Kd);
            flash_byte_program(user_data_addr + user_data_offset + 12, user_data->scr_save_time);
            flash_byte_program(user_data_addr + user_data_offset + 13, user_data->shutdown_time);
            flash_byte_program(user_data_addr + user_data_offset + 14, user_data->select_data.data);
            flash_byte_program(user_data_addr + user_data_offset + 15, user_data->free_data);

            flash_lock();

            /* 退出临界区 */
            taskEXIT_CRITICAL();

            return;
        }

        user_data_offset = user_data_offset + sizeof(user_save_data);

        if(user_data_offset > (sector_size - sizeof(user_save_data))) {                 //数据存储空间满，擦除扇区
            /* 进入临界区 */
            taskENTER_CRITICAL();

            //擦除存储用户数据的扇区
            flash_unlock();
            flash_sector_erase(user_data_addr);
            flash_lock();

            /* 退出临界区 */
            taskEXIT_CRITICAL();

            user_data_offset = 0;
        }
    }
}


/**
  * @brief    音频发声
  * @param    音频频率
  * @param    音频持续时间
  * @retval   None
  */
void tone(uint16_t freq, uint16_t time_ms)
{
    uint16_t audio_cycles;

    TONE_OFF();
    audio_cycles = 1000000 / freq;
    tmr_base_init(TMR11, audio_cycles, 143);
    tmr_channel_value_set(TMR11, TMR_SELECT_CHANNEL_1, audio_cycles / 32);      //audio_cycles/x  改变x可以调整音量大小
    TONE_ON();
    #if USE_RTOS
    vTaskDelay(time_ms);
    #else
    wk_delay_ms(time_ms);
    #endif
    tmr_channel_value_set(TMR11, TMR_SELECT_CHANNEL_1, 0);  //关闭定时器前，先将通道值清零，避免出现杂音
    TONE_OFF();
}


/**
  * @brief    音乐播放函数
  * @param    乐谱数据指针，乐符数量
  * @retval   None
  */
void music(const uint16_t *music_data, uint16_t length)
{
    uint16_t i;

    for(i = 0; i < length; i++) {
        tone(*(music_data + i * 2), *(music_data + i * 2 + 1));
    }
}

/* 显示界面函数 */
/**
  * @brief    控制界面重绘
  * @param    None
  * @retval   None
  */
void Control_interface_redraw(void)
{
    char string_buff[32];

    ssd1306_Fill(Black);                    //清屏
    ssd1306_DrawRectangle(0, 0, 127, 63, White);
    ssd1306_Line(0, 18, 127, 18, White);
    ssd1306_Line(0, 36, 127, 36, White);
    ssd1306_Line(54, 0, 54, 36, White);

    sprintf(string_buff, "%02d.%01dC", (uint8_t)set_temp, (uint8_t)((set_temp - (uint8_t)set_temp) * 10));
    ssd1306_SetCursor(2, 2);

    if(ctrl_start == 0) {
        ssd1306_WriteString(string_buff, Font_16x15, White);
    } else {
        ssd1306_WriteString(string_buff, Font_16x15, Black);
    }

    sprintf(string_buff, "%01dd%02d:%02d", set_time / 1440, (set_time / 60) % 24, set_time % 60);
    ssd1306_SetCursor(56, 2);

    if(ctrl_start == 0) {
        ssd1306_WriteString(string_buff, Font_16x15, White);
    } else {
        ssd1306_WriteString(string_buff, Font_16x15, Black);
    }

    //显示当前电压值
    voltage = get_voltage_value();    //获取电压值
    sprintf(string_buff, "%02d.%01dV", voltage / 1000, (voltage % 1000) / 100);
    ssd1306_SetCursor(2, 20);
    ssd1306_WriteString(string_buff, Font_16x15, White);

    //显示加热时长
    sprintf(string_buff, "%1dd%02d:%02d", current_time / 1440, (current_time % 1440) / 60, current_time % 60);
    ssd1306_SetCursor(56, 20);
    ssd1306_WriteString(string_buff, Font_16x15, White);

    ssd1306_UpdateScreen();         //刷新屏幕
}

/**
  * @brief    控制界面刷新
  * @param    None
  * @retval   None
  */
void Control_interface_refresh(void)
{
    char string_buff[32];
    static uint8_t count_1s = 0;
    static uint8_t count_display = 0;

    //以下为显示任务
    sprintf(string_buff, "%02d.%01dC", (uint8_t)set_temp, (uint8_t)((set_temp - (uint8_t)set_temp) * 10));
    ssd1306_SetCursor(2, 2);

    if(ctrl_start == 0) {
        ssd1306_WriteString(string_buff, Font_16x15, White);
    } else {
        ssd1306_WriteString(string_buff, Font_16x15, Black);
    }

    sprintf(string_buff, "%01dd%02d:%02d", set_time / 1440, (set_time / 60) % 24, set_time % 60);
    ssd1306_SetCursor(56, 2);

    if(ctrl_start == 0) {
        ssd1306_WriteString(string_buff, Font_16x15, White);
    } else {
        ssd1306_WriteString(string_buff, Font_16x15, Black);
    }



    if(count_display < 10) {
        //显示当前电压值
        sprintf(string_buff, "%02d.%01dV", voltage / 1000, (voltage % 1000) / 100);
        ssd1306_SetCursor(2, 20);
        ssd1306_WriteString(string_buff, Font_16x15, White);

        //显示温湿度数据
        if((user_save_data.select_data.sensor_select == 0) || (user_save_data.select_data.sensor_select == 2)) {
            //显示A参数
            if(shtxx_t_A < 0.00f) {
                sprintf(string_buff, "A--.--");
            } else {
                sprintf(string_buff, "A%.2f", shtxx_t_A);
            }

            ssd1306_SetCursor(6, 42);
            ssd1306_WriteString(string_buff, Font_11x18, White);

            //显示当前湿度值
            sprintf(string_buff, "%02d%%", (uint8_t)shtxx_h_A);
            ssd1306_SetCursor(85, 42);
            ssd1306_WriteString(string_buff, Font_11x18, White);
        } else {
            //显示B参数
            if(shtxx_t_B < 0.00f) {
                sprintf(string_buff, "B--.--");
            } else {
                sprintf(string_buff, "B%.2f", shtxx_t_B);
            }

            ssd1306_SetCursor(6, 42);
            ssd1306_WriteString(string_buff, Font_11x18, White);

            //显示当前湿度值
            sprintf(string_buff, "%02d%%", (uint8_t)shtxx_h_B);
            ssd1306_SetCursor(85, 42);
            ssd1306_WriteString(string_buff, Font_11x18, White);
        }
    } else {
        //显示当前模式
        if(user_save_data.select_data.mode_select == 0) sprintf(string_buff, "%s", "Temp");
        else sprintf(string_buff, "%s", "CTRL");

        ssd1306_SetCursor(2, 20);
        ssd1306_WriteString(string_buff, Font_16x15, White);

        //显示温湿度数据
        if((user_save_data.select_data.sensor_select == 1) || (user_save_data.select_data.sensor_select == 2)) {
            //显示B参数
            if(shtxx_t_B < 0.00f) {
                sprintf(string_buff, "B--.--");
            } else {
                sprintf(string_buff, "B%.2f", shtxx_t_B);
            }

            ssd1306_SetCursor(6, 42);
            ssd1306_WriteString(string_buff, Font_11x18, White);

            //显示当前湿度值
            sprintf(string_buff, "%02d%%", (uint8_t)shtxx_h_B);
            ssd1306_SetCursor(85, 42);
            ssd1306_WriteString(string_buff, Font_11x18, White);
        } else {
            //显示A参数
            if(shtxx_t_A < 0.00f) {
                sprintf(string_buff, "A--.--");
            } else {
                sprintf(string_buff, "A%.2f", shtxx_t_A);
            }

            ssd1306_SetCursor(6, 42);
            ssd1306_WriteString(string_buff, Font_11x18, White);

            //显示当前湿度值
            sprintf(string_buff, "%02d%%", (uint8_t)shtxx_h_A);
            ssd1306_SetCursor(85, 42);
            ssd1306_WriteString(string_buff, Font_11x18, White);
        }
    }

    if(count_display < 20) count_display++;
    else count_display = 0;
    
    if(error_count > 0) {       //数据读取有错误
        sprintf(string_buff, "%s", "Error");
        ssd1306_SetCursor(2, 20);
        ssd1306_WriteString(string_buff, Font_16x15, Black);
    }

    //显示加热时长
    if((count_1s == 1) && (ctrl_start == 1)) {  //温控开始，时间显示冒号闪动
        count_1s = 0;
        sprintf(string_buff, "%1dd%02d %02d", current_time / 1440, (current_time % 1440) / 60, current_time % 60);
    } else {
        count_1s = 1;
        sprintf(string_buff, "%1dd%02d:%02d", current_time / 1440, (current_time % 1440) / 60, current_time % 60);
    }

    ssd1306_SetCursor(56, 20);
    ssd1306_WriteString(string_buff, Font_16x15, White);

    ssd1306_UpdateScreen();         //刷新屏幕

    //在主界面刷新中，检查自动关机条件
    if((user_save_data.select_data.mode_select == 0) && (user_save_data.shutdown_time >= 5)) {
        if(Shutdown_count > user_save_data.shutdown_time) {
            ssd1306_SetDisplayOn(0);	//关闭屏幕显示
            ssd1306_shutdown();			//屏幕进入掉电模式
            LED_OFF();

            enter_standby_mode();		//进入待机模式
        }
    }
}


/**
  * @brief    温度曲线界面重绘
  * @param    None
  * @retval   None
  */
void Chart_interface_redraw(void)
{
    char string_buff[32];

    set_pos = 0;
    temp_chart_range = 50;
    temp_chart_refreshcycle = 1;

    ssd1306_Fill(Black);                    //清屏
    ssd1306_Line(2, 12, 2, 63, White);
    ssd1306_Line(2, 63, 127, 63, White);
    ssd1306_Line(0, 37, 1, 37, White);

    for(uint8_t i = 0; i < 125; i++) {
        if(i % 8 == 0) ssd1306_DrawPixel(i + 2, 37, White);
    }

    sprintf(string_buff, "Chart");
    ssd1306_SetCursor(47, 0);
    ssd1306_WriteString(string_buff, Font_7x10, White);

    sprintf(string_buff, "R%04d", temp_chart_range);
    ssd1306_SetCursor(2, 2);
    
    ssd1306_UpdateScreen();         //刷新屏幕
}

/**
  * @brief    温度曲线界面刷新
  * @param    None
  * @retval   None
  */
void Chart_interface_refresh(void)
{
    char string_buff[32];
    int16_t t0;

    //以下为显示任务
    if(Refresh_flag == 1) {                      //判断有新的温度数据进入缓冲区，则重绘曲线
        sprintf(string_buff, "R%04d", temp_chart_range);    //刷新参数显示
        ssd1306_SetCursor(2, 2);

        if(set_pos == 0) {
            ssd1306_WriteString(string_buff, Font_7x10, Black);
            ssd1306_Line(2, 1, 36, 1, White);
        } else {
            ssd1306_WriteString(string_buff, Font_7x10, White);
            ssd1306_Line(2, 1, 36, 1, Black);
        }

        sprintf(string_buff, "T%03d", temp_chart_refreshcycle);
        ssd1306_SetCursor(100, 2);

        if(set_pos == 1) {
            ssd1306_WriteString(string_buff, Font_7x10, Black);
            ssd1306_Line(100, 1, 127, 1, White);
        } else {
            ssd1306_WriteString(string_buff, Font_7x10, White);
            ssd1306_Line(100, 1, 127, 1, Black);
        }

        ssd1306_FillRectangle(3, 12, 127, 62, Black);       //清除上次显示曲线

        for(uint8_t i = 0; i < 125; i++) {
            if(i % 8 == 0) ssd1306_DrawPixel(i + 2, 37, White);
        }

        for(uint8_t i = 0; i < 125; i++) {                  //计算刷新一屏的温度数据
            chart_buff[i].x = i + 3;
            
            switch (temp_chart_refreshcycle)
            {
            	case 1:
                    t0 = temp1s_buff[i] - (int16_t)(set_temp * 100.0f);
            		break;
            	case 2:
                    t0 = temp2s_buff[i] - (int16_t)(set_temp * 100.0f);
            		break;
                case 5:
                    t0 = temp5s_buff[i] - (int16_t)(set_temp * 100.0f);
            		break;
            	case 15:
                    t0 = temp15s_buff[i] - (int16_t)(set_temp * 100.0f);
            		break;
                case 30:
                    t0 = temp30s_buff[i] - (int16_t)(set_temp * 100.0f);
            		break;
            	case 60:
                    t0 = temp1m_buff[i] - (int16_t)(set_temp * 100.0f);
            		break;
                case 300:
                    t0 = temp5m_buff[i] - (int16_t)(set_temp * 100.0f);
            		break;
            	case 600:
                    t0 = temp10m_buff[i] - (int16_t)(set_temp * 100.0f);
            		break;
                case 900:
                    t0 = temp15m_buff[i] - (int16_t)(set_temp * 100.0f);
            		break;

            	default:
                    t0 = temp1s_buff[i] - (int16_t)(set_temp * 100.0f);
            		break;
            }

            if(t0 >= 0) {
                if((37 - t0 / (temp_chart_range / 25)) >= 12) {
                    chart_buff[i].y = 37 - t0 / (temp_chart_range / 25);
                } else {
                    chart_buff[i].y = 12;
                }
            } else {
                t0 = abs(t0);

                if((37 + t0 / (temp_chart_range / 25)) <= 62) {
                    chart_buff[i].y = 37 + t0 / (temp_chart_range / 25);
                } else {
                    chart_buff[i].y = 63;
                }
            }
        }

        ssd1306_Polyline((const SSD1306_VERTEX *)chart_buff, 125, White);
    }
    
    Refresh_flag = 0;
    ssd1306_UpdateScreen();         //刷新屏幕
}


/**
  * @brief    菜单界面重绘
  * @param    None
  * @retval   None
  */
void Menu_interface_redraw(void)
{
    clear_all_button_flag();

    //设置参数初始化
    set_temp_int = (uint8_t)set_temp;
    set_temp_fractional = (uint8_t)((set_temp - (float)set_temp_int) * 100.0f);

    alarm_temp_int = (uint8_t)alarm_temp;
    alarm_temp_fractional = (uint8_t)((alarm_temp - (float)alarm_temp_int) * 100.0f);

    set_day = set_time / 1440;
    set_hour = (set_time / 60) % 24;
    set_minute = set_time % 60;

    set_pos = 0;

    Refresh_flag = 1;       //进入菜单设置界面先刷一次屏
}


/**
  * @brief    菜单界面刷新
  * @param    None
  * @retval   None
  */
void Menu_interface_refresh(void)
{
//    char string_buff[32];
    uint8_t i, m;

    ssd1306_Fill(Black);                    //清屏

    if(user_save_data.select_data.mode_select == 0)
        sprintf(menu_value_string[0], "%s", "temp");
    else
        sprintf(menu_value_string[0], "%s", "ctrl");

    sprintf(menu_value_string[1], "%02d.%02dC", set_temp_int, set_temp_fractional);
    sprintf(menu_value_string[2], "%02d.%02dC", alarm_temp_int, alarm_temp_fractional);
    sprintf(menu_value_string[3], "%01dd %02d:%02d", set_day, set_hour, set_minute);
    sprintf(menu_value_string[4], "%.1f", (float)user_save_data.Kp / 10.0f);
    sprintf(menu_value_string[5], "%.2f", (float)user_save_data.Ki / 100.0f);
    sprintf(menu_value_string[6], "%.1f", (float)user_save_data.Kd / 10.0f);
    sprintf(menu_value_string[7], "%03dm", user_save_data.scr_save_time);
    sprintf(menu_value_string[8], "%03ds", user_save_data.shutdown_time);

    if(user_save_data.select_data.sensor_select == 0)
        sprintf(menu_value_string[9], "%s", "A");
    else if(user_save_data.select_data.sensor_select == 1)
        sprintf(menu_value_string[9], "%s", "B");
    else if(user_save_data.select_data.sensor_select == 2)
        sprintf(menu_value_string[9], "%s", "A+B");

    if(user_save_data.select_data.filter_mode == 0)
        sprintf(menu_value_string[10], "%s", " No");
    else if(user_save_data.select_data.filter_mode == 1)
        sprintf(menu_value_string[10], "%s", "Yes");

    if(Current_line < 4) m = 0;
    else m = Current_line - 3;

    for(i = m; i < (4 + m); i++) {
        ssd1306_SetCursor(0, (i - m) * 16);

        if(Current_line == i) {
            ssd1306_WriteString((char *)menu_string[i], Font_8x16, Black);

            if(set_pos > 0) {
                ssd1306_SetCursor(52 + (8 - strlen(menu_value_string[i])) * 7, (i - m) * 16);
                ssd1306_WriteString((char *)menu_value_string[i], Font_8x16, Black);
            } else {
                ssd1306_SetCursor(52 + (8 - strlen(menu_value_string[i])) * 7, (i - m) * 16);
                ssd1306_WriteString((char *)menu_value_string[i], Font_8x16, White);
            }
        } else {
            ssd1306_WriteString((char *)menu_string[i], Font_8x16, White);
            ssd1306_SetCursor(52 + (8 - strlen(menu_value_string[i])) * 7, (i - m) * 16);
            ssd1306_WriteString((char *)menu_value_string[i], Font_8x16, White);
        }
    }

    ssd1306_UpdateScreen();         //刷新屏幕
}


/**
  * @brief    设置参数存储
  * @param    None
  * @retval   None
  */
void Menu_setup_update(void)
{
    set_temp = (float)set_temp_int + (float)set_temp_fractional / 100.0f + 0.00005f;        //加一个小数，消除转换误差
    alarm_temp = (float)alarm_temp_int + (float)alarm_temp_fractional / 100.0f + 0.00005f;  //加一个小数，消除转换误差
    set_time = set_day * 1440 + set_hour * 60 + set_minute;

    //保存用户数据到flash
    user_save_data.user_set_temp = set_temp_int * 100 + set_temp_fractional;
    user_save_data.user_alarm_temp = alarm_temp_int * 100 + alarm_temp_fractional;
    user_save_data.user_set_time = set_time;

    Shutdown_count = 0;         //自动关机计数器清零

    save_user_data(&user_save_data);
}


/**
  * @brief    告警温度检查
  * @param    None
  * @retval   None
  */
void alarm_temp_check(void)
{
    if(user_save_data.select_data.mode_select != 0) return;     //不是温度计模式，直接返回

    if(user_save_data.select_data.sensor_select == 0) {
        if(shtxx_t_A > (float)(user_save_data.user_alarm_temp / 100) + (float)(user_save_data.user_alarm_temp % 100) / 100.0f) { //发现温度高于系统设定告警温度，发出提示音
            alarm_status_flag = 1;
        }
    } else if((user_save_data.select_data.sensor_select == 1) || (user_save_data.select_data.sensor_select == 2)) {
        if(shtxx_t_B > (float)(user_save_data.user_alarm_temp / 100) + (float)(user_save_data.user_alarm_temp % 100) / 100.0f) { //发现温度高于系统设定告警温度，发出提示音
            alarm_status_flag = 1;
        }
    }

    return;
}


/**
  * @brief    温度读取错误处理
  * @param    None
  * @retval   None
  */
void temp_read_error(void)
{
    error_count++;
    i2c_config(&hi2c2_SHT30);       //尝试复位I2C总线恢复数据传输
    
    if(error_count > ERROR_COUNT_MAX) {                         //修复次数达到最大值后，关闭温控、并发出提示音
        ctrl_start = 0;             //关闭温控
        timed_comp_flag = 1;        //定时完成标志置位
        alarm_status_flag = 1;      //告警提示音标志置位
        tmr_channel_value_set(TMR10, TMR_SELECT_CHANNEL_1, 0);  //关闭加热板
        LED_OFF();
    }

    return;
}


/*  FreeRTOS任务函数  */
/**
  * @brief    button任务
  * @param    None
  * @retval   None
  */
void button_task_function(void *pvParameters)
{
    clear_all_button_flag();

    while (1) {
        switch (Interface_flag) {
            case 0:             //控制界面按键处理
                if(BUTTON_SHORT_PRESS_Flag == 1) {        //button长按，进入菜单设置界面
                    clear_all_button_flag();
                    Interface_flag = 2;
                    alarm_status_flag = 0;      //关闭告警提示音标志
                    ctrl_start = 0;             //进入设置菜单，关闭恒温加热
                    Menu_interface_redraw();    //重绘菜单设置界面
                    music(tone2, sizeof(tone2) / 4);
                }

                if(K2_SHORT_PRESS_Flag == 1) {
                    clear_all_button_flag();
                    Interface_flag = 1;
                    Chart_interface_redraw();
                    tone(500, 500);
                }

                if(BUTTON_SINGLE_Click_Flag == 1) {        //button单击，启动/停止恒温控制
                    clear_all_button_flag();

                    if((ctrl_start == 0) && (alarm_status_flag == 1)) {     //停止恒温控制，且报警的情况下，单击关闭告警音
                        alarm_status_flag = 0;
                    } else if((ctrl_start == 0) && (Screensavers_status == 0) && (user_save_data.select_data.mode_select == 1)) {
                        ctrl_start = 1;             //启动恒温控制
                        current_time = 0;           //当前计数时间清零
                        alarm_status_flag = 0;
                        timed_comp_flag = 0;
                        PID_Init(&mypid, user_save_data.Kp, user_save_data.Ki, user_save_data.Kd, 1500, 3200); //初始化PID参数

                        music(tone0, sizeof(tone0) / 4);
                    } else if((ctrl_start == 1) && (Screensavers_status == 0) && (user_save_data.select_data.mode_select == 1)) {
                        ctrl_start = 0;             //停止恒温控制
                        music(tone1, sizeof(tone1) / 4);
                    } else {
                        tone(1000, 50);             //关闭屏保
                    }
                }

                if((K1_SINGLE_Click_Flag == 1) || (K2_SINGLE_Click_Flag == 1)) {  //关闭告警音
                    clear_all_button_flag();

                    if(Screensavers_status == 0) {
                        alarm_status_flag = 0;
                    }

                    tone(1000, 50);
                }

                break;

            case 1:             //温度曲线界面按键处理
                if(K1_SHORT_PRESS_Flag == 1) {
                    clear_all_button_flag();
                    Interface_flag = 0;
                    Control_interface_redraw();     //重绘控制界面
                    tone(500, 500);
                }

                if(BUTTON_SINGLE_Click_Flag) {      //切换参数
                    clear_all_button_flag();

                    if(Screensavers_status == 0) {
                        set_pos++;

                        if(set_pos > 1) set_pos = 0;
                    }
                    Refresh_flag = 1;
                    tone(1000, 50);
                }

                if(K1_SINGLE_Click_Flag) {
                    clear_all_button_flag();

                    if(Screensavers_status == 0) {
                        switch (set_pos) {
                            case 0:
                                if(temp_chart_range == 50) temp_chart_range = 2000;
                                else if(temp_chart_range == 100) temp_chart_range = 50;
                                else if(temp_chart_range == 200) temp_chart_range = 100;
                                else if(temp_chart_range == 500) temp_chart_range = 200;
                                else if(temp_chart_range == 1000) temp_chart_range = 500;
                                else if(temp_chart_range == 2000) temp_chart_range = 1000;

                                break;

                            case 1:
                                if(temp_chart_refreshcycle == 1) temp_chart_refreshcycle = 900;
                                else if(temp_chart_refreshcycle == 2) temp_chart_refreshcycle = 1;
                                else if(temp_chart_refreshcycle == 5) temp_chart_refreshcycle = 2;
                                else if(temp_chart_refreshcycle == 15) temp_chart_refreshcycle = 5;
                                else if(temp_chart_refreshcycle == 30) temp_chart_refreshcycle = 15;
                                else if(temp_chart_refreshcycle == 60) temp_chart_refreshcycle = 30;
                                else if(temp_chart_refreshcycle == 300) temp_chart_refreshcycle = 60;
                                else if(temp_chart_refreshcycle == 600) temp_chart_refreshcycle = 300;
                                else if(temp_chart_refreshcycle == 900) temp_chart_refreshcycle = 600;

                                break;

                            default:
                                break;
                        }
                    }
                    Refresh_flag = 1;
                    tone(1000, 50);
                }

                if(K2_SINGLE_Click_Flag) {
                    clear_all_button_flag();

                    if(Screensavers_status == 0) {
                        switch (set_pos) {
                            case 0:
                                if(temp_chart_range == 50) temp_chart_range = 100;
                                else if(temp_chart_range == 100) temp_chart_range = 200;
                                else if(temp_chart_range == 200) temp_chart_range = 500;
                                else if(temp_chart_range == 500) temp_chart_range = 1000;
                                else if(temp_chart_range == 1000) temp_chart_range = 2000;
                                else if(temp_chart_range == 2000) temp_chart_range = 50;

                                break;

                            case 1:
                                if(temp_chart_refreshcycle == 1) temp_chart_refreshcycle = 2;
                                else if(temp_chart_refreshcycle == 2) temp_chart_refreshcycle = 5;
                                else if(temp_chart_refreshcycle == 5) temp_chart_refreshcycle = 15;
                                else if(temp_chart_refreshcycle == 15) temp_chart_refreshcycle = 30;
                                else if(temp_chart_refreshcycle == 30) temp_chart_refreshcycle = 60;
                                else if(temp_chart_refreshcycle == 60) temp_chart_refreshcycle = 300;
                                else if(temp_chart_refreshcycle == 300) temp_chart_refreshcycle = 600;
                                else if(temp_chart_refreshcycle == 600) temp_chart_refreshcycle = 900;
                                else if(temp_chart_refreshcycle == 900) temp_chart_refreshcycle = 1;

                                break;

                            default:
                                break;
                        }
                    }
                    Refresh_flag = 1;
                    tone(1000, 50);
                }

                break;

            case 2:             //设置界面按键处理
                if(BUTTON_SHORT_PRESS_Flag == 1) {        //button长按，返回控制界面
                    clear_all_button_flag();
                    Interface_flag = 0;
                    Menu_setup_update();            //菜单设置更新
                    Control_interface_redraw();     //重绘控制界面
                    music(tone3, sizeof(tone3) / 4);
                }

                if(BUTTON_SINGLE_Click_Flag == 1) {      //参数项选择
                    clear_all_button_flag();

                    switch (Current_line) {
                        case 0:
                            if(set_pos < 1) set_pos++;
                            else set_pos = 0;

                            break;

                        case 1:
                            if(set_pos < 2) set_pos++;
                            else set_pos = 0;

                            break;

                        case 2:
                            if(set_pos < 2) set_pos++;
                            else set_pos = 0;

                            break;

                        case 3:
                            if(set_pos < 3) set_pos++;
                            else set_pos = 0;

                            break;

                        case 4:
                            if(set_pos < 1) set_pos++;
                            else set_pos = 0;

                            break;

                        case 5:
                            if(set_pos < 1) set_pos++;
                            else set_pos = 0;

                            break;

                        case 6:
                            if(set_pos < 1) set_pos++;
                            else set_pos = 0;

                            break;

                        case 7:
                            if(set_pos < 1) set_pos++;
                            else set_pos = 0;

                            break;

                        case 8:
                            if(set_pos < 1) set_pos++;
                            else set_pos = 0;

                            break;

                        case 9:
                            if(set_pos < 1) set_pos++;
                            else set_pos = 0;

                            break;
                        case 10:
                            if(set_pos < 1) set_pos++;
                            else set_pos = 0;

                            break;
                    }

                    Refresh_flag = 1;
                    tone(1000, 50);
                }

                if(K2_SINGLE_Click_Flag == 1) {          //右键单击
                    clear_all_button_flag();

                    switch (set_pos) {
                        case 0:
                            if(Current_line < MENU_ITEM_MAX - 1)
                                Current_line++;
                            else
                                Current_line = 0;

                            break;

                        case 1:
                            switch (Current_line) {
                                case 0:
                                    if(user_save_data.select_data.mode_select < 1) user_save_data.select_data.mode_select = 1;
                                    else user_save_data.select_data.mode_select = 0;

                                    break;

                                case 1:
                                    if(set_temp_int < SET_TEMP_MAX) set_temp_int++;

                                    break;

                                case 2:
                                    if(alarm_temp_int < ALARM_TEMP_MAX) alarm_temp_int++;

                                    break;

                                case 3:
                                    if(set_day < 6) set_day++;

                                    break;

                                case 4:
                                    if(user_save_data.Kp < 30000) user_save_data.Kp += 10;

                                    break;

                                case 5:
                                    if(user_save_data.Ki < 10000) user_save_data.Ki ++;

                                    break;

                                case 6:
                                    if(user_save_data.Kd < 30000) user_save_data.Kd += 10;

                                    break;

                                case 7:
                                    if(user_save_data.scr_save_time < 255) user_save_data.scr_save_time++;

                                    break;

                                case 8:
                                    if(user_save_data.shutdown_time < 255) user_save_data.shutdown_time++;

                                    break;

                                case 9:
                                    if(user_save_data.select_data.sensor_select < 2) user_save_data.select_data.sensor_select++;
                                    else user_save_data.select_data.sensor_select = 0;

                                    break;

                                case 10:
                                    if(user_save_data.select_data.filter_mode < 1) user_save_data.select_data.filter_mode++;
                                    else user_save_data.select_data.filter_mode = 0;

                                    break;
                            }

                            break;

                        case 2:
                            switch (Current_line) {
                                case 1:
                                    if(set_temp_fractional < 90) set_temp_fractional += 10;
                                    else set_temp_fractional = 0;

                                    break;

                                case 2:
                                    if(alarm_temp_fractional < 90) alarm_temp_fractional += 10;
                                    else alarm_temp_fractional = 0;

                                    break;

                                case 3:
                                    if(set_hour < 23) set_hour++;
                                    else set_hour = 0;

                                    break;
                            }

                            break;

                        case 3:
                            switch (Current_line) {
                                case 3:
                                    if(set_minute < 59) set_minute++;
                                    else set_minute = 0;

                                    break;
                            }

                            break;
                    }

                    Refresh_flag = 1;
                    tone(1000, 50);
                }

                if(K2_LONG_PRESS_Flag == 1) {       //右键长按
                    clear_all_button_flag();

                    switch (set_pos) {
                        case 0:
                            break;

                        case 1:
                            switch (Current_line) {
                                case 1:
                                    if(set_temp_int < ((uint8_t)SET_TEMP_MAX) - 5) set_temp_int = set_temp_int % 5 ? set_temp_int + (5 - set_temp_int % 5) : set_temp_int + 5;

                                    break;

                                case 2:
                                    if(alarm_temp_int < ((uint8_t)ALARM_TEMP_MAX) - 5) alarm_temp_int = alarm_temp_int % 5 ? alarm_temp_int + (5 - alarm_temp_int % 5) : alarm_temp_int + 5;

                                    break;

                                case 3:
                                    if(set_day < 6) set_day++;

                                    break;

                                case 4:
                                    if(user_save_data.Kp < 30000) user_save_data.Kp += 100;

                                    break;

                                case 5:
                                    if(user_save_data.Ki < 10000) user_save_data.Ki += 10;

                                    break;

                                case 6:
                                    if(user_save_data.Kd < 30000) user_save_data.Kd += 100;

                                    break;

                                case 7:
                                    if(user_save_data.scr_save_time < 255 - 10) user_save_data.scr_save_time = user_save_data.scr_save_time % 10 ? user_save_data.scr_save_time + (10 - user_save_data.scr_save_time % 10) : user_save_data.scr_save_time + 10;

                                    break;

                                case 8:
                                    if(user_save_data.shutdown_time < 255 - 10) user_save_data.shutdown_time = user_save_data.shutdown_time % 10 ? user_save_data.shutdown_time + (10 - user_save_data.shutdown_time % 10) : user_save_data.shutdown_time + 10;

                                    break;
                            }

                            break;

                        case 2:
                            switch (Current_line) {
                                case 1:
                                    if(set_temp_fractional < 90) set_temp_fractional += 10;
                                    else set_temp_fractional = 0;

                                    break;

                                case 2:
                                    if(alarm_temp_fractional < 90) alarm_temp_fractional += 10;
                                    else alarm_temp_fractional = 0;

                                    break;

                                case 3:
                                    if(set_hour < 22) set_hour = set_hour % 2 ? set_hour + (2 - set_hour % 2) : set_hour + 2;
                                    else set_hour = 0;

                                    break;
                            }

                            break;

                        case 3:
                            switch (Current_line) {
                                case 3:
                                    if(set_minute < 55) set_minute = set_minute % 5 ? set_minute + (5 - set_minute % 5) : set_minute + 5;
                                    else set_minute = 0;

                                    break;
                            }

                            break;
                    }

                    Refresh_flag = 1;
                    tone(1000, 50);
                    vTaskDelay(500);
                }

                if(K1_SINGLE_Click_Flag == 1) {          //左键单击
                    clear_all_button_flag();

                    switch (set_pos) {
                        case 0:
                            if(Current_line != 0)
                                Current_line--;
                            else
                                Current_line = MENU_ITEM_MAX - 1;

                            Refresh_flag = 1;
                            break;

                        case 1:
                            switch (Current_line) {
                                case 0:
                                    if(user_save_data.select_data.mode_select > 0) user_save_data.select_data.mode_select--;
                                    else user_save_data.select_data.mode_select = 1;

                                    break;

                                case 1:
                                    if(set_temp_int > 0) set_temp_int--;

                                    break;

                                case 2:
                                    if(alarm_temp_int > 0) alarm_temp_int--;

                                    break;

                                case 3:
                                    if(set_day > 0) set_day--;

                                    break;

                                case 4:
                                    if(user_save_data.Kp > 10) user_save_data.Kp -= 10;

                                    break;

                                case 5:
                                    if(user_save_data.Ki > 0) user_save_data.Ki --;

                                    break;

                                case 6:
                                    if(user_save_data.Kd > 10) user_save_data.Kd -= 10;

                                    break;

                                case 7:
                                    if(user_save_data.scr_save_time > 2) user_save_data.scr_save_time--;

                                    break;

                                case 8:
                                    if(user_save_data.shutdown_time > 5) user_save_data.shutdown_time--;

                                    break;

                                case 9:
                                    if(user_save_data.select_data.sensor_select > 0) user_save_data.select_data.sensor_select--;
                                    else user_save_data.select_data.sensor_select = 2;

                                    break;
                                
                                case 10:
                                    if(user_save_data.select_data.filter_mode > 1) user_save_data.select_data.filter_mode--;
                                    else user_save_data.select_data.filter_mode = 0;

                                    break;
                            }

                            break;

                        case 2:
                            switch (Current_line) {
                                case 1:
                                    if(set_temp_fractional > 9) set_temp_fractional -= 10;
                                    else set_temp_fractional = 90;

                                    break;

                                case 2:
                                    if(alarm_temp_fractional > 9) alarm_temp_fractional -= 10;
                                    else alarm_temp_fractional = 90;

                                    break;

                                case 3:
                                    if(set_hour > 0) set_hour--;
                                    else set_hour = 23;

                                    break;
                            }

                            break;

                        case 3:
                            switch (Current_line) {
                                case 3:
                                    if(set_minute > 0) set_minute--;
                                    else set_minute = 59;

                                    break;
                            }

                            break;
                    }

                    Refresh_flag = 1;
                    tone(1000, 50);
                }

                if(K1_LONG_PRESS_Flag == 1) {       //左键长按
                    clear_all_button_flag();

                    switch (set_pos) {
                        case 0:
                            break;

                        case 1:
                            switch (Current_line) {
                                case 1:
                                    if(set_temp_int >= 5) set_temp_int = set_temp_int % 5 ? set_temp_int - set_temp_int % 5 : set_temp_int - 5;

                                    break;

                                case 2:
                                    if(alarm_temp_int >= 5) alarm_temp_int = alarm_temp_int % 5 ? alarm_temp_int - alarm_temp_int % 5 : alarm_temp_int - 5;

                                    break;

                                case 3:
                                    if(set_day > 0) set_day--;

                                    break;

                                case 4:
                                    if(user_save_data.Kp >= 100) user_save_data.Kp -= 100;

                                    break;

                                case 5:
                                    if(user_save_data.Ki >= 10) user_save_data.Ki -= 10;

                                    break;

                                case 6:
                                    if(user_save_data.Kd >= 100) user_save_data.Kd -= 100;

                                    break;

                                case 7:
                                    if(user_save_data.scr_save_time >= 12) user_save_data.scr_save_time -= 10;

                                    break;

                                case 8:
                                    if(user_save_data.shutdown_time >= 20) user_save_data.shutdown_time -= 10;

                                    break;
                            }

                            break;

                        case 2:
                            switch (Current_line) {
                                case 1:
                                    if(set_temp_fractional > 9) set_temp_fractional -= 10;
                                    else set_temp_fractional = 90;

                                    break;

                                case 2:
                                    if(alarm_temp_fractional > 9) alarm_temp_fractional -= 10;
                                    else alarm_temp_fractional = 90;

                                    break;

                                case 3:
                                    if(set_hour >= 2) set_hour = set_hour % 2 ? set_hour - set_hour % 2 : set_hour - 2;
                                    else set_hour = 22;

                                    break;
                            }

                            break;

                        case 3:
                            switch (Current_line) {
                                case 3:
                                    if(set_minute > 0) set_minute = set_minute % 5 ? set_minute - set_minute % 5 : set_minute - 5;
                                    else set_minute = 55;

                                    break;
                            }

                            break;
                    }

                    Refresh_flag = 1;
                    tone(1000, 50);
                    vTaskDelay(500);
                }

                break;
        }

        if(alarm_status_flag == 1) {    //告警提示音
            tone(1000, 80);
            vTaskDelay(1000);
        }

//        alarm_temp_check();             //高温告警检查
        vTaskDelay(10);
    }
}

/**
  * @brief    检测控制任务
  *           100ms运行一次检测控制
  * @param    None
  * @retval   None
  */
void detect_task_function(void *pvParameters)
{
    static uint8_t count_1s = 0;
    static uint64_t old_second = 0;
    uint8_t i;
    uint16_t temp_val;
    float temp_val_float;
    float humid_val_float;

    while (1) {
        voltage = get_voltage_value();                                              //获取电压值

        if(user_save_data.select_data.sensor_select == 0) {
            if(SHT30_Read_Temperature_Humidity((float *)&temp_val_float, (float *)&humid_val_float, 1) == ERROR) {  //获取内置传感器温湿度值
                //温度读取错误处理
                temp_read_error();
            }
            else {
                error_count = 0;    //传输恢复，计数器清零
            }
            temp_val_float = temp_val_float * Temp_coeff;                                           //校正板载传感器温度值
            if((user_save_data.select_data.mode_select == 1) && (user_save_data.select_data.filter_mode == 1)){
                shtxx_t_A = KalmanFilter_A_temperature.updateEstimate(&KalmanFilter_A_temperature, temp_val_float);
                shtxx_h_A = KalmanFilter_A_humidity.updateEstimate(&KalmanFilter_A_humidity, humid_val_float);
            }else {
                shtxx_t_A = temp_val_float;
                shtxx_h_A = humid_val_float;
            }
            shtxx_t_B = -45.0f;
            shtxx_h_B = 0.0f;
            temp_val = (int16_t)(shtxx_t_A * 100.0f);
        } else if(user_save_data.select_data.sensor_select == 1) {
            if(SHT30_Read_Temperature_Humidity((float *)&temp_val_float, (float *)&humid_val_float, 0) == ERROR) {  //获取外置传感器温湿度值
                //温度读取错误处理
                temp_read_error();
            }
            else {
                error_count = 0;    //传输恢复，计数器清零
            }
            if((user_save_data.select_data.mode_select == 1) && (user_save_data.select_data.filter_mode == 1)){
                shtxx_t_B = KalmanFilter_B_temperature.updateEstimate(&KalmanFilter_B_temperature, temp_val_float);
                shtxx_h_B = KalmanFilter_B_humidity.updateEstimate(&KalmanFilter_B_humidity, humid_val_float);
            }else {
                shtxx_t_B = temp_val_float;
                shtxx_h_B = humid_val_float;
            }
            shtxx_t_A = -45.0f;
            shtxx_h_A = 0.0f;
            temp_val = (int16_t)(shtxx_t_B * 100.0f);
        } else if(user_save_data.select_data.sensor_select == 2) {
            if(SHT30_Read_Temperature_Humidity((float *)&temp_val_float, (float *)&humid_val_float, 1) == ERROR) {  //获取内置传感器温湿度值
                //温度读取错误处理
                temp_read_error();
            }
            else {
                error_count = 0;    //传输恢复，计数器清零
            }
            temp_val_float = temp_val_float * Temp_coeff;                                           //校正板载传感器温度值
            if((user_save_data.select_data.mode_select == 1) && (user_save_data.select_data.filter_mode == 1)){
                shtxx_t_A = KalmanFilter_A_temperature.updateEstimate(&KalmanFilter_A_temperature, temp_val_float);
                shtxx_h_A = KalmanFilter_A_humidity.updateEstimate(&KalmanFilter_A_humidity, humid_val_float);
            }else {
                shtxx_t_A = temp_val_float;
                shtxx_h_A = humid_val_float;
            }
            if(SHT30_Read_Temperature_Humidity((float *)&temp_val_float, (float *)&humid_val_float, 0) == ERROR) {  //获取外置传感器温湿度值
                //温度读取错误处理
                temp_read_error();
            }
            else {
                error_count = 0;    //传输恢复，计数器清零
            }
            if((user_save_data.select_data.mode_select == 1) && (user_save_data.select_data.filter_mode == 1)){
                shtxx_t_B = KalmanFilter_B_temperature.updateEstimate(&KalmanFilter_B_temperature, temp_val_float);
                shtxx_h_B = KalmanFilter_B_humidity.updateEstimate(&KalmanFilter_B_humidity, humid_val_float);
            }else {
                shtxx_t_B = temp_val_float;
                shtxx_h_B = humid_val_float;
            }
            
            temp_val = (int16_t)(shtxx_t_B * 100.0f);
        }

        if((current_time > (set_time - 1)) && (timed_comp_flag == 0)) {             //定时时间到，关闭恒温控制
            ctrl_start = 0;             //关闭温控
            timed_comp_flag = 1;        //定时完成标志置位
            alarm_status_flag = 1;      //告警提示音标志置位
        }

        if(old_second != current_second) { 
            for(i=124; i>0; i--) {                                          //1s采样缓冲区
                temp1s_buff[i] = temp1s_buff[i-1];
            }
            temp1s_buff[0] = temp_val;
            
            if(current_second%2 == 0) {                                     //2s采样缓冲区
                for(i=124; i>0; i--) {
                    temp2s_buff[i] = temp2s_buff[i-1];
                }
                temp2s_buff[0] = (temp1s_buff[0] + temp1s_buff[1]) / 2;     //保存均值
            }
            
            if(current_second%5 == 0) {                                     //5s采样缓冲区
                for(i=124; i>0; i--) {
                    temp5s_buff[i] = temp5s_buff[i-1];
                }
                temp5s_buff[0] = (temp1s_buff[0] + temp1s_buff[1] + temp1s_buff[2] + temp1s_buff[3] + temp1s_buff[4]) / 5;     //保存均值
            }
            
            if(current_second%15 == 0) {                                     //15s采样缓冲区
                for(i=124; i>0; i--) {
                    temp15s_buff[i] = temp15s_buff[i-1];
                }
                temp15s_buff[0] = (temp5s_buff[0] + temp5s_buff[1] + temp5s_buff[3]) / 3;     //保存均值
            }
            
            if(current_second%30 == 0) {                                     //30s采样缓冲区
                for(i=124; i>0; i--) {
                    temp30s_buff[i] = temp30s_buff[i-1];
                }
                temp30s_buff[0] = (temp15s_buff[0] + temp15s_buff[1]) / 2;     //保存均值
            }
            
            if(current_second%60 == 0) {                                     //60s采样缓冲区
                for(i=124; i>0; i--) {
                    temp1m_buff[i] = temp1m_buff[i-1];
                }
                temp1m_buff[0] = (temp30s_buff[0] + temp30s_buff[1]) / 2;     //保存均值
            }
            
            if(current_second%300 == 0) {                                     //300s采样缓冲区
                for(i=124; i>0; i--) {
                    temp5m_buff[i] = temp5m_buff[i-1];
                }
                temp5m_buff[0] = (temp1m_buff[0] + temp1m_buff[1] + temp1m_buff[2] + temp1m_buff[3] + temp1m_buff[4]) / 5;     //保存均值
            }
            
            if(current_second%600 == 0) {                                     //600s采样缓冲区
                for(i=124; i>0; i--) {
                    temp10m_buff[i] = temp10m_buff[i-1];
                }
                temp10m_buff[0] = (temp5m_buff[0] + temp5m_buff[1]) / 2;     //保存均值
            }
            
            if(current_second%900 == 0) {                                     //900s采样缓冲区
                for(i=124; i>0; i--) {
                    temp15m_buff[i] = temp15m_buff[i-1];
                }
                temp15m_buff[0] = (temp5m_buff[0] + temp5m_buff[1] + temp5m_buff[2]) / 3;     //保存均值
            }  
            if(current_second%temp_chart_refreshcycle == 0) {
                Refresh_flag = 1;
            }
            old_second = current_second;
        }


        if(ctrl_start == 1) {                           //判断恒温控制是否启动
            if(user_save_data.select_data.sensor_select == 0) {     //使用内置传感器参数
                PID_Calc(&mypid, set_temp, shtxx_t_A);  //进行PID计算，结果在output成员变量中
            } else {                                    //使用外置传感器参数
                PID_Calc(&mypid, set_temp, shtxx_t_B);  //进行PID计算，结果在output成员变量中
            }

            pwm_value = (int16_t)(mypid.output * 10.0f);    //PID结果乘以比例系数计算加热板控制值

            if(pwm_value < 0) pwm_value = 0;                //控制值小于零停止加热

            if(pwm_value > 9999) pwm_value = 9999;          //超出控制最大值，则控制值恒定为最大值

            if(count_1s > 9) {
                count_1s = 0;
                tmr_channel_value_set(TMR10, TMR_SELECT_CHANNEL_1, pwm_value);      //输出控制值，对加热板进行控制

                if(pwm_value > 0) LED_ON();                 //加热指示灯显示，亮灯：启动加热    灭灯：停止加热
                else LED_OFF();

                if(user_save_data.select_data.sensor_select == 0) {     //根据传感器的选择，串口输出不同的数据
                    printf("%.2f\n", shtxx_t_A);
                } else if(user_save_data.select_data.sensor_select == 1) {
                    printf("%.2f\n", shtxx_t_B);
                } else if(user_save_data.select_data.sensor_select == 2) {
                    printf("%.2f,%.2f\n", shtxx_t_A, shtxx_t_B);
                }
            }
        } else {
            tmr_channel_value_set(TMR10, TMR_SELECT_CHANNEL_1, 0);              //关闭加热板
            LED_OFF();
        }

        count_1s++;

        alarm_temp_check();             //高温告警检查
        vTaskDelay(100);
    }
}

/**
  * @brief    串口任务
  * @param    None
  * @retval   None
  */
void usart_task_function(void *pvParameters)
{

    while (1) {

        vTaskDelay(1);
    }
}

/**
  * @brief    显示任务
  * @param    None
  * @retval   None
  */
void display_task_function(void *pvParameters)
{
    //初始化用户参数
    get_user_data(&user_save_data);
    set_temp = (float)(user_save_data.user_set_temp / 100) + (float)(user_save_data.user_set_temp % 100) / 100.0f;
    alarm_temp = (float)(user_save_data.user_alarm_temp / 100) + (float)(user_save_data.user_alarm_temp % 100) / 100.0f;
    set_time = user_save_data.user_set_time;

    //启动开门狗
    wdt_enable();

    Control_interface_redraw();                 //开始任务循环前，先绘制控制界面
//    music(tone0, sizeof(tone0)/4);              //开机音乐

    while (1) {
        if(Screensavers_count <= (user_save_data.scr_save_time <= 5 ? 1 : (user_save_data.scr_save_time/3))) { //屏幕保护控制
            if(Screensavers_status != 0) {      //设定时间<5分钟则一分钟以内正常显示，设定时间>5分钟则屏保时间三分之一以内正常显示
                ssd1306_SetContrast(128);
                ssd1306_SetDisplayOn(1);
                Screensavers_status = 0;
                tone(1000, 50);
            }
        } else if(Screensavers_count <= user_save_data.scr_save_time) {    //设定时间内低亮度显示
            if(Screensavers_status != 1) {
                ssd1306_SetContrast(1);
                Screensavers_status = 1;
                tone(1000, 50);
            }
        } else {
            if(Screensavers_status != 2) {      //大于设定时间无按键操作，关闭显示屏
                ssd1306_SetDisplayOn(0);
                Screensavers_status = 2;
                tone(1000, 1000);
            }

            LED_ON();                           //亮灯提示设备工作中
        }

        switch (Interface_flag) {
            case 0:
                Control_interface_refresh();    //刷新控制界面
                break;

            case 1:
                if(Refresh_flag == 1) {
                    Chart_interface_refresh();      //温度曲线刷新函数
                    Refresh_flag = 0;
                }
                break;

            case 2:
                if(Refresh_flag == 1) {
                    Menu_interface_refresh();       //刷新菜单界面
                    Refresh_flag = 0;
                }

                break;

            default:
                break;
        }

        wdt_counter_reload();           //喂狗

        vTaskDelay(500);
    }
}


/**
  * @brief    FreeRTOS任务初始化函数
  * @param    None
  * @retval   None
  */
void Task_Init(void)
{
    /* 进入临界区 */
    taskENTER_CRITICAL();

    /* Key processing task */
    xTaskCreate((TaskFunction_t)button_task_function,
                (const char *)"button_task",
                (uint16_t)160,
                (void *)NULL,
                (UBaseType_t)4,
                (TaskHandle_t *)NULL);

    /* detect task */
    xTaskCreate((TaskFunction_t)detect_task_function,
                (const char *)"detect_task",
                (uint16_t)160,
                (void *)NULL,
                (UBaseType_t)3,
                (TaskHandle_t *)NULL);

    /* usart task */
//    xTaskCreate((TaskFunction_t)usart_task_function,
//                (const char *)"usart_task",
//                (uint16_t)512,
//                (void *)NULL,
//                (UBaseType_t)4,
//                (TaskHandle_t *)NULL);

    /* display task */
    xTaskCreate((TaskFunction_t)display_task_function,
                (const char *)"display_task",
                (uint16_t)256,
                (void *)NULL,
                (UBaseType_t)2,
                (TaskHandle_t *)NULL);

    /* 退出临界区 */
    taskEXIT_CRITICAL();
}


